
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Scanner;
import javax.swing.JOptionPane;
import javax.swing.JPanel;


/**
 * Call different build class according to user input.
 * @author Robert C. Duvall revised by Difan Zhao
 */

public class Factory {
    /**
     * myBuildObj is a map that registered all the build class.
     */
    private HashMap<String, Build> myBuildObj;
    private HashMap<String, ApplyForce> myApplyForce;
   // private HashMap<String, HashMap<String, Build>> functionMap;
    private static volatile Factory factory;

    /**
     * Create a hashmap between all types of object and buildObject method.
     */
    public Factory () {
        myBuildObj = new HashMap<String, Build>();
        myBuildObj.put("mass", new BuildMass());
        myBuildObj.put("spring", new BuildSpring());
        myBuildObj.put("muscle", new BuildMuscle());
        
        
        myApplyForce = new HashMap<String, ApplyForce>();
        myApplyForce.put("gravity", new ApplyGravity());
        myApplyForce.put("viscosity", new ApplyViscosity());
        myApplyForce.put("centermass", new ApplyCenterMass());
        ApplyWallForce wallForce=new ApplyWallForce();
        myApplyForce.put("wall", wallForce);
        for (int i=1;i<5;i++){
            String keyName="wall"+i;
            myApplyForce.put(keyName, wallForce.getWallForce(i));
        }
        
        
    /*  //  System.out.println()
        functionMap=new HashMap<String, HashMap<String, Build>>();
        functionMap.put("object", myBuildObj);
        functionMap.put("force", myApplyForce);
        */
        
    }
    
    public static Factory getFactory(){
        if(factory==null){
           factory = new Factory();
        }
        
        return factory;
    }

    /**
     * Call build class to create material object.
     * @param sim simulator
     * @param modelFile data file.
     */
    public void loadModel (Simulation sim, File modelFile) {
        try {
            Scanner input = new Scanner(modelFile);
            while (input.hasNext()) {
                Scanner line = new Scanner(input.nextLine());
                if (line.hasNext()) {
                    String type = line.next();
                    if (!myBuildObj.containsKey(type)) {
                        errorMessage("Object undefined!");
                        System.exit(0);
                    }
                    else {
                        myBuildObj.get(type).build(line, sim);
                    }
                }
            }
            input.close();
        }
        catch (FileNotFoundException e) {
            // should not happen because File came from user selection
            e.printStackTrace();
        }
    }
    
    public void loadForce (Simulation sim, File modelFile) {
        try {
            Scanner input = new Scanner(modelFile);
            while (input.hasNext()) {
                Scanner line = new Scanner(input.nextLine());
                if (line.hasNext()) {
                    String type = line.next();
                    if (!myApplyForce.containsKey(type)) {
                        errorMessage("Force undefined!");
                        System.exit(0);
                    }
                    else {
                       myApplyForce.get(type).build(line, sim);
                    }
                }
            }
            input.close();
        }
        catch (FileNotFoundException e) {
            // should not happen because File came from user selection
            e.printStackTrace();
        }
    }
    
    public ArrayList<ApplyForce> getApplicableForce(){
        ArrayList<ApplyForce> list = new ArrayList<ApplyForce>(myApplyForce.values());
        return list;
    }
    
    
    /*
    
    public void loadObject (Simulation sim, File file, String function) {
        
        try {
            Scanner input = new Scanner(file);
            HashMap<String, Build> map=functionMap.get(function);
            while (input.hasNext()) {
                Scanner line = new Scanner(input.nextLine());
                if (line.hasNext()) {
                   
                    String type = line.next();
                    if(! map.containsKey(type)){
                        errorMessage( function+" undefined!");
                        System.exit(0);
                        
                    }else{
                       map.get(type).build(line, sim);
                    }
                }
            }
            input.close();
        }
        catch (FileNotFoundException e) {
            // should not happen because File came from user selection
            e.printStackTrace();
        }
        
        
            
        
    }
    
    */
    /**
     * Popup error message.
     * @param error string
     */
    public void errorMessage (String error) {
        final JPanel panel = new JPanel();
        JOptionPane.showMessageDialog(panel, error, "Error",
                JOptionPane.ERROR_MESSAGE);
    }

}
